{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this notebook the individual stages of learning of Gobnilp are shown. We start by creating a Gobnilp object, printing out (the tuple of) stages and also the stage we are in just after creating the Gobnilp object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using license file /home/james/gurobi.lic\n",
      "Academic license - for non-commercial use only\n",
      "Changed value of parameter PreCrush to 1\n",
      "   Prev: 0  Min: 0  Max: 1  Default: 0\n",
      "Changed value of parameter CutPasses to 100000\n",
      "   Prev: -1  Min: -1  Max: 2000000000  Default: -1\n",
      "Changed value of parameter GomoryPasses to 100000\n",
      "   Prev: -1  Min: -1  Max: 2000000000  Default: -1\n",
      "Changed value of parameter MIPFocus to 2\n",
      "   Prev: 0  Min: 0  Max: 3  Default: 0\n",
      "Changed value of parameter ZeroHalfCuts to 2\n",
      "   Prev: -1  Min: -1  Max: 2  Default: -1\n",
      "Changed value of parameter MIPGap to 0.0\n",
      "   Prev: 0.0001  Min: 0.0  Max: inf  Default: 0.0001\n",
      "Changed value of parameter MIPGapAbs to 0.0\n",
      "   Prev: 1e-10  Min: 0.0  Max: inf  Default: 1e-10\n",
      "('no data', 'data', 'local scores', 'MIP model', 'MIP solution', 'BN(s)', 'CPDAG(s)', 'output shown', 'output written')\n",
      "Gobnilp stage = no data, Gurobi status = 1\n"
     ]
    }
   ],
   "source": [
    "from pygobnilp.gobnilp import Gobnilp\n",
    "m = Gobnilp()\n",
    "print(m.stages)\n",
    "print(m.stage)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So we start at the `no data` stage, so let's get some data. A typical way to obtain data is to read it in from a file, so let's do that and stop the learning process at the next stage, by specifying that next stage - `data` - as the `end` of the learning process."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "m.learn('discrete.dat',end='data')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now we have data, it can be inspected."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The type of the \"data\" attribute is <class 'pandas.core.frame.DataFrame'>\n",
      "The type of the \"rawdata\" attribute is <class 'numpy.ndarray'>\n",
      "The variables for the data are ('A', 'B', 'C', 'D', 'E', 'F')\n",
      "Here are the first two datapoints:\n",
      "   A  B  C  D  E  F\n",
      "0  0  0  0  0  0  0\n",
      "1  0  1  1  0  0  0\n",
      "Here are the first two datapoints:\n",
      "[[0 0 0 0 0 0]\n",
      " [0 1 1 0 0 0]]\n"
     ]
    }
   ],
   "source": [
    "print('The type of the \"data\" attribute is {0}'.format(type(m.data)))\n",
    "print('The type of the \"rawdata\" attribute is {0}'.format(type(m.rawdata)))\n",
    "print('The variables for the data are {0}'.format(m.data_variables))\n",
    "print('Here are the first two datapoints:\\n{0}'.format(m.data[:2]))\n",
    "print('Here are the first two datapoints:\\n{0}'.format(m.rawdata[:2]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So the data can either be accessed as a Pandas dataframe or a Numpy array. Use whichever\n",
    "is more convenient. We can now move on another stage by computing local scores. We specify that we `start` at the `data` stage. Had we not done that the default of `start='no data'` would be used (and since no data is specified an error would be raised)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "dict_keys(['A', 'B', 'C', 'D', 'E', 'F'])\n",
      "{frozenset(): -5502.137377150637, frozenset({'B'}): -4349.791324894952, frozenset({'D'}): -4376.2801910701055, frozenset({'E'}): -5289.02870426271, frozenset({'D', 'B'}): -3504.4066187025273, frozenset({'D', 'C'}): -3589.495045030806, frozenset({'D', 'E'}): -4244.150479815038, frozenset({'F', 'E'}): -5288.503190060048, frozenset({'D', 'C', 'B'}): -3013.608073856336}\n"
     ]
    }
   ],
   "source": [
    "m.learn(start='data',end='local scores')\n",
    "print(m.local_scores.keys())\n",
    "print(m.local_scores['A'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we can construct a MIP model - creating MIP variables and constraints. Let's do that, and then print out the dictionary of family variables with child A and then inspect and alter the MIP family variable which indicates that A has B as its only parent."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{frozenset(): <gurobi.Var A<-{}>, frozenset({'B'}): <gurobi.Var A<-{B}>, frozenset({'D'}): <gurobi.Var A<-{D}>, frozenset({'E'}): <gurobi.Var A<-{E}>, frozenset({'D', 'B'}): <gurobi.Var A<-{B,D}>, frozenset({'D', 'C'}): <gurobi.Var A<-{C,D}>, frozenset({'D', 'E'}): <gurobi.Var A<-{D,E}>, frozenset({'F', 'E'}): <gurobi.Var A<-{E,F}>, frozenset({'D', 'C', 'B'}): <gurobi.Var A<-{B,C,D}>}\n",
      "<gurobi.Var A<-{B}> 0.0 1.0 -4349.791324894952\n",
      "<gurobi.Var A<-{B}> 1.0 1.0 -4349.791324894952\n"
     ]
    }
   ],
   "source": [
    "m.learn(start='local scores',end='MIP model')\n",
    "print(m.family['A'])\n",
    "v = m.family['A'][frozenset(['B'])]\n",
    "print(v,v.lb,v.ub,v.Obj)\n",
    "v.lb = 1   # fix variable to 1 by setting 1 as its lower bound\n",
    "m.update() # have to update now for new lower bound to take effect immediately\n",
    "print(v,v.lb,v.ub,v.Obj)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's solve the MIP instance. Before doing so we set the attribute `Params.OutputFlag` to `True` so we can see Gurobi at work. `Params.OutputFlag` is an attribute of the Gurobi Model class which we can access since the Gobnilp class is a subclass of the Gurobi Model class. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Changed value of parameter OutputFlag to 1\n",
      "   Prev: 0  Min: 0  Max: 1  Default: 1\n"
     ]
    }
   ],
   "source": [
    "m.Params.OutputFlag = True\n",
    "m.learn(start='MIP model',end='MIP solution')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since this is an easy problem it is solved immediately. We can then see which variables have been set to non-zero values, using the `X` attribute of each variable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<gurobi.Var A<-{B} (value 1.0)>\n",
      "<gurobi.Var B<-{} (value 1.0)>\n",
      "<gurobi.Var C<-{} (value 1.0)>\n",
      "<gurobi.Var D<-{A,C} (value 1.0)>\n",
      "<gurobi.Var E<-{B,F} (value 1.0)>\n",
      "<gurobi.Var F<-{} (value 1.0)>\n",
      "<gurobi.Var A->D (value 1.0)>\n",
      "<gurobi.Var B->A (value 1.0)>\n",
      "<gurobi.Var B->E (value 1.0)>\n",
      "<gurobi.Var C->D (value 1.0)>\n",
      "<gurobi.Var F->E (value 1.0)>\n",
      "<gurobi.Var A-B (value 1.0)>\n",
      "<gurobi.Var A-D (value 1.0)>\n",
      "<gurobi.Var B-E (value 1.0)>\n",
      "<gurobi.Var C-D (value 1.0)>\n",
      "<gurobi.Var E-F (value 1.0)>\n"
     ]
    }
   ],
   "source": [
    "for x in m.getVars():\n",
    "    if x.X > 0:\n",
    "        print(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Sure enough, the family variable `A<-{B}` which we fixed to 1 is set to 1 in the solution obtained. Note that as well as family variables Gobnilp has created arrow and undirected edge indicator variables. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The next stage is to convert the MIP solution into a BN, which we can then print out and plot."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pygobnilp.gobnilp.BN'>\n",
      "**********\n",
      "BN has score -24028.0947783535\n",
      "**********\n",
      "A<-B -4349.791324894952\n",
      "B<- -4841.285573475907\n",
      "C<- -3501.5105385969146\n",
      "D<-A,C -3555.014444236549\n",
      "E<-B,F -4310.304956470649\n",
      "F<- -3470.18794067853\n",
      "**********\n",
      "bnlearn modelstring = \n",
      "[A|B][B][C][D|A:C][E|F:B][F]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "m.learn(start='MIP solution',end='BN(s)')\n",
    "print(type(m.learned_bn))\n",
    "print(m.learned_bn)\n",
    "m.learned_bn.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next we can create a CPDAG to represent the Markov equivalence class containing the learned BN. The CPDAG is just the BN where we compute which edges are *compelled* to take the same direction in each Markov equivalent BN. Once this has been done (by progressing from the 'BN(s)' stage to the 'CPDAG(s)' stage) we can use the cpdag_str method to get a string representation of the CPDAG and if we plot the BN the compelled edges will be in red."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "**********\n",
      "CPDAG:\n",
      "Vertices: A,B,C,D,E,F\n",
      "A->D\n",
      "B-A\n",
      "B->E\n",
      "C->D\n",
      "F->E\n",
      "\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "m.learn(start='BN(s)',end='CPDAG(s)')\n",
    "print(m.learned_bn.cpdag_str())\n",
    "m.learned_bn.plot()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A CPDAG has directed and undirected edges, but in the plot of the CPDAG we only see directed ones which are either black or red. The black edges in the CPDAG should be interpreted as undirected. The reason for plotting the CPDAG in this non-standard manner is that it allows one plot to represent both the learned BN (just ignore the colours) and the learned CPDAG (interpret black edges as undirected).\n",
    "\n",
    "The last Gobnilp stages are `output_shown` and `output_written` but since we have already 'manually' shown the output there is no reason here to progress to those stages."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
